<!DOCTYPE HTML>
<html>
<head>
<title>OnExit | AutoHotkey</title>
<meta name="description" content="The OnExit function specifies a callback function or subroutine to run automatically when the script exits." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
<script type="text/javascript">$(function(){0<=window.navigator.userAgent.toLowerCase().indexOf("ucbrowser")&&CaoNiMaDeUc()})</script>
</head>
<body>

<h1>OnExit</h1>
<p>指定一个在脚本退出时自动运行的<a href="../Functions.htm">回调函数</a>或<a href="Gosub.htm">子程序</a>.</p>

<h2 id="function">OnExit() <span class="ver">[v1.1.20+]</span></h2>
<pre class="Syntax"><span class="func">OnExit</span>(Func <span class="optional">, AddRemove</span>)</pre>

<h3>参数</h3>
<dl>

  <dt>Func</dt>
  <dd><p>脚本退出时调用的函数名称或<a href="../objects/Functor.htm">函数对象</a>. 该函数还可以有选择的定义参数, 请参考下面的例子. 如果 OnExit 调用的函数返回一个非零整数, 脚本将不会继续退出. 否则, 脚本将在所有注册函数运行完成之后退出.</p>
  <pre class="Syntax"><span class="func">ExitFunc</span>(<a href="#ExitReason">ExitReason</a>, <a href="ExitApp.htm">ExitCode</a>)</pre></dd>
  
  <dt>AddRemove</dt>
  <dd><p>下列值之一:<br>
  <strong>1</strong>(默认): 在所有之前注册的函数之后调用该函数.<br>
  <strong>-1</strong>: 在所有之前注册的函数之前调用该函数.<br>
  <strong>0 </strong>: 不调用该函数.</p>
  <p>总是优先调用已注册的 label(标签)(子程序).</p>
  </dd>

</dl>

<h3>备注</h3>
<p>新脚本使用函数替代原来的子程序 --  这样可以降低脚本无法退出的风险, 并确保传递给 Exit 或 ExitApp 的退出码被保存.</p>
<p>OnExit 函数可以注册任意多个. 如果同时还注册了 label(子程序), 注册的这些函数会在子程序执行 <a href="ExitApp.htm">ExitApp</a> 命令之后被调用. 通常 OnExit 函数不需要调用 ExitApp 命令; 如果调用了, 脚本将会立即退出.</p>

<h3 id="Examples">示例</h3>
<pre class="NoIndent"><em>; 脚本启动之后, 在托盘图标上点击鼠标右键和选择 <em>Exit</em> 来测试 OnExit 回调函数.</em>
<a href="_Persistent.htm">#Persistent</a>  <em>; 防止脚本自动退出.</em>

<em>; 注册一个在退出时调用的函数:</em>
OnExit("ExitFunc")

<em>; 注册一个在退出时调用的对象:</em>
OnExit(<a href="ObjBindMethod.htm">ObjBindMethod</a>(MyObject, "Exiting"))

ExitFunc(ExitReason, ExitCode)
{
    if ExitReason not in Logoff,Shutdown
    {
        MsgBox, 4, , Are you sure you want to exit?
        IfMsgBox, No
            return 1  <em>; OnExit 函数必须返回非零值来防止退出.</em>
    }
    <em>; 不要用 ExitApp -- 那会阻止其他 OnExit 函数被调用.</em>
}

class MyObject
{
    Exiting()
    {
        MsgBox, MyObject is cleaning up prior to exiting...
        <em>/*
        this.SayGoodbye()
        this.CloseNetworkConnections()
        */</em>
    }
}</pre>

<h2 id="command">OnExit</h2>
<p class="warning"><strong>不推荐:</strong> 不推荐在新脚本中使用此命令. 使用 <a href="#function">OnExit</a> 函数代替.</p>
<pre class="Syntax"><span class="func">OnExit</span> <span class="optional">, Label</span></pre>

<h3>参数</h3>
<dl>

  <dt>Label</dt>
  <dd><p>如果省略, 则脚本会返回到正常的退出行为. 否则, 请指定 <a href="../misc/Labels.htm">label(标签)</a> 的名称, 当脚本由于任意原因退出时将执行标签中的内容(作为新<a href="../misc/Threads.htm">线程</a>).</p></dd>

</dl>

<h3>备注</h3>
<p><strong>重要提示:</strong> 由于指定的子程序被调用而不是退出脚本, 因此如果需要退出脚本, 子程序中必须使用 <a href="ExitApp.htm">ExitApp</a> 命令. (译者注: 每次遇到退出, 就执行子程序, 相当于退出命令被子程序取代了而不会被执行, 不过在子程序运行时(完成之前), 再次选择退出时, 不会再次调用子程序, 而是退出, 详情请参阅下面的备注.)</p>
<p>内置变量 <strong>A_ExitReason</strong> 为空, 除非 OnExit 子程序正在运行或者在之前的退出中至少调用过一次. 如果不是空的, 则它为<a href="#ExitReason">下面表格</a>中单词的其中一个.</p>

<h3>示例</h3>
<pre class="NoIndent"><em>; 脚本启动之后, 在托盘图标上点击鼠标右键和选择 Exit 来测试 OnExit 回调函数.</em>
<a href="_Persistent.htm">#Persistent</a>  <em>; 防止脚本自动退出.</em>
OnExit, ExitSub  
return

ExitSub:
if A_ExitReason not in Logoff,Shutdown  <em>; 在这行语句中, 注意不要在逗号周围含有空格.</em>
{
    MsgBox, 4, , Are you sure you want to exit?
    IfMsgBox, No
        return
}
ExitApp  <em>; 脚本含有 OnExit 子程序时不会立即终止, 除非子程序使用 ExitApp.</em></pre>

<h2>备注</h2>
<p>当脚本以任何方式退出时, 将调用 OnExit 回调函数或子程序(除非被类似 &quot;结束任务&quot; 的方式强行终止). 每当 <a href="_SingleInstance.htm">#SingleInstance</a> 和 <a href="Reload.htm">Reload</a> 命令请求前一个实例终止时, 也会调用它.</p>
<p>脚本可以通过 <code>OnMessage(0x11, &quot;WM_QUERYENDSESSION&quot;)</code>(有关工作脚本, 请参阅 <a href="OnMessage.htm#shutdown">OnMessage 示例 #2</a>) 检测并可选择地中止操作系统关闭或注销.</p>
<p>OnExit <a href="../misc/Threads.htm">线程</a>并不受到 <a href="_MaxThreads.htm">#MaxThreads</a> 的限制(它总是在需要的时候启动). 此外, 当它运行时, 它不会被任何<a href="../misc/Threads.htm">线程</a>中断, 包括<a href="../Hotkeys.htm">热键</a>, <a href="Menu.htm">自定义菜单项</a>和<a href="SetTimer.htm">计时器子程序</a>. 不过, 它会在这些情况下被中断(终止)(且脚本也同时被终止了): 用户从托盘菜单或主菜单栏中选择 exit(退出), 或由于 <a href="Reload.htm">Reload</a> 或 <a href="_SingleInstance.htm">#SingleInstance</a> 而要求脚本终止. 由于这些原因, OnExit 回调函数或子程序应该被设计为尽快结束, 除非用户知道它在做什么.</p>
<p>如果 OnExit <a href="../misc/Threads.htm">线程</a>遇到失败条件, 比如运行时错误时, 脚本将会终止. 这可以防止有缺陷的 OnExit 回调函数或子程序使脚本无法终止.</p>
<p>如果 OnExit <a href="../misc/Threads.htm">线程</a>由 <a href="Exit.htm">Exit</a> 或 <a href="ExitApp.htm">ExitApp</a> 启动并指定了退出码, 在 <span class="ver">[v1.1.19]</span> 和之前的版本中将被忽略, 且不再可用. 而从 <span class="ver">[v1.1.20+]</span> 开始, 除非使用 <a href="ExitApp.htm">ExitApp</a> 指定了新的退出码, 否则将使用最初的退出码.</p>
<p>每当进行一个退出尝试时, 每个 OnExit 回调函数或子程序都将以 <a href="SendMode.htm">SendMode</a> 等设置的默认值启动. 这些默认值可以在<a href="../Scripts.htm#auto">自动执行段</a>中更改.</p>

<h2 id="ExitReason">ExitReason(退出原因)</h2>
<table class="info">
  <tr id="logoff">
    <td>logoff</td>
    <td>用户正在注销.</td>
  </tr>
  <tr>
    <td>Shutdown</td>
    <td>正在关闭或重启系统, 例如使用 <a href="Shutdown.htm">Shutdown</a> 命令.</td>
  </tr>
  <tr>
    <td>Close</td>
    <td>脚本发送 WM_CLOSE 或 WM_QUIT 消息, 出现致命错误, 或者正在被其他方式关闭. 尽管这些情况都是很少见的, 然而 WM_CLOSE 可能是由于在脚本主窗口中使用 <a href="WinClose.htm">WinClose</a> 命令而引起的. 要关闭(隐藏) 窗口而不终止脚本, 请使用 <a href="WinHide.htm">WinHide</a>.</td>
  </tr>
  <tr>
    <td>Error</td>
    <td>在没有热键且不是<a href="_Persistent.htm">持续运行的</a>脚本中发生了运行时错误. 运行时错误的一个例子是 <a href="Run.htm">Run/RunWait</a> 命令无法启动指定的程序或打开指定的文档.</td>
  </tr>
  <tr>
    <td>Menu</td>
    <td>用户在主窗口的菜单或标准托盘菜单中选择了退出.</td>
  </tr>
  <tr>
    <td>Exit</td>
    <td>使用了 <a href="Exit.htm">Exit</a> 或 <a href="ExitApp.htm">ExitApp</a> 命令(包括 <a href="Menu.htm">自定义菜单项</a>).</td>
  </tr>
  <tr>
    <td>Reload</td>
    <td>正通过 <a href="Reload.htm">Reload</a> 命令或菜单项重载脚本.</td>
  </tr>
  <tr>
    <td>Single</td>
    <td>由于 <a href="_SingleInstance.htm">#SingleInstance</a> 的结果, 脚本正被它自身的新实例代替.</td>
  </tr>
</table>

<h2>相关</h2>
<p><a href="OnError.htm">OnError()</a>, <a href="OnMessage.htm">OnMessage()</a>, <a href="RegisterCallback.htm">RegisterCallback()</a>, <a href="OnClipboardChange.htm">OnClipboardChange</a>, <a href="ExitApp.htm">ExitApp</a>, <a href="Shutdown.htm">Shutdown</a>, <a href="_Persistent.htm">#Persistent</a>, <a href="../misc/Threads.htm">Threads</a>, <a href="Gosub.htm">Gosub</a>, <a href="Return.htm">Return</a>, <a href="Menu.htm">Menu</a></p>

</body>
</html>